package com.djmw.mouse.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.persistence.DynamicSpecifications;
import org.springside.modules.persistence.SearchFilter;
import org.springside.modules.persistence.SearchFilter.Operator;

import com.djmw.mouse.PageSizeDef;
import com.djmw.mouse.entity.HrUser;
import com.djmw.mouse.entity.Position;
import com.djmw.mouse.entity.PositionHistory;
import com.djmw.mouse.entity.PositionSolr;
import com.djmw.mouse.repository.PositionDao;
import com.djmw.mouse.repository.PositionHistoryDao;
import com.djmw.mouse.solr.PositionDaoSolr;

//Spring Bean的标识.
@Component
// 默认将类中的所有public函数纳入事务管理.
@Transactional(readOnly = true)
public class PositionService {

    @Autowired
    private PositionDao positionDao;
    @Autowired
    private PositionHistoryDao positionHistoryDao;
    @Autowired
    private PositionDaoSolr positionDaoSolr;

    public Position getPosition(Long id) {
        return positionDao.findOne(id);
    }

    @Transactional(readOnly = false)
    public void savePosition(Position entity, HrUser hrUser) {
        positionDao.save(entity);
        if (hrUser != null) {
            PositionHistory history = new PositionHistory(entity, hrUser, new Date());
            positionHistoryDao.save(history);
        }
        positionDaoSolr.save(new PositionSolr(entity));
    }

    @Transactional(readOnly = false)
    public void deletePosition(Long id, HrUser hrUser) {
        positionDao.changeStatus(id, Position.STATUS_DELETED);
        saveHistory(id, hrUser, new Date());
    }

    @Transactional(readOnly = false)
    public void enablePosition(Long id, HrUser hrUser) {
        positionDao.changeStatus(id, Position.STATUS_ENABLED);
        saveHistory(id, hrUser, new Date());
    }

    @Transactional(readOnly = false)
    public void disablePosition(Long id, HrUser hrUser) {
        positionDao.changeStatus(id, Position.STATUS_DISABLED);
        saveHistory(id, hrUser, new Date());
    }

    private void saveHistory(Long positionId, HrUser hrUser, Date datetime) {
        Position entity = positionDao.findOne(positionId);
        PositionHistory history = new PositionHistory(entity, hrUser, new Date());
        positionHistoryDao.save(history);
    }

    public Page<Position> getPosition(Map<String, Object> searchParams, int pageNumber, int pageSize, String sortType,
            String sortDir) {
        PageRequest pageRequest = buildPageRequest(pageNumber, pageSize, sortType, sortDir);
        Specification<Position> spec = buildSpecification(searchParams);
        return positionDao.findAll(spec, pageRequest);
    }

    public Page<Position> getCompanyPosition(Long companyId) {
        return getCompanyPosition(companyId, new HashMap<String, Object>(), 1, PageSizeDef.MAX_PAGE_SIZE, "auto", "d");
    }

    public Page<Position> getCompanyPosition(Long companyId, Map<String, Object> searchParams, int pageNumber,
            int pageSize, String sortType, String sortDir) {
        return getCompanyPosition(companyId, searchParams, pageNumber, pageSize, sortType, sortDir, false);
    }

    public Page<Position> getCompanyPosition(Long companyId, Map<String, Object> searchParams, int pageNumber,
            int pageSize, String sortType, String sortDir, boolean includeDeletedPosition) {
        PageRequest pageRequest = buildPageRequest(pageNumber, pageSize, sortType, sortDir);
        Specification<Position> spec = buildCompanySpecification(companyId, searchParams, includeDeletedPosition);

        return positionDao.findAll(spec, pageRequest);
    }

    /**
     * 创建分页请求.
     */
    private PageRequest buildPageRequest(int pageNumber, int pagzSize, String sortType, String sortDir) {
        Sort sort = null;
        if ("auto".equals(sortType)) {
            sort = new Sort(Direction.DESC, "id");
        } else {
            sort = new Sort("d".equalsIgnoreCase(sortDir) ? Direction.DESC : Direction.ASC, sortType);
        }

        return new PageRequest(pageNumber - 1, pagzSize, sort);
    }

    /**
     * 创建动态查询条件组合.
     */
    private Specification<Position> buildSpecification(Map<String, Object> searchParams) {
        Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
        Specification<Position> spec = DynamicSpecifications.bySearchFilter(filters.values(), Position.class);
        return spec;
    }

    private Specification<Position> buildCompanySpecification(Long companyId, Map<String, Object> searchParams,
            boolean includeDeletedPosition) {
        Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
        filters.put("company.id", new SearchFilter("company.id", Operator.EQ, companyId));
        if (!includeDeletedPosition) {
            filters.put("status", new SearchFilter("status", Operator.LT, Position.STATUS_DELETED));
        }
        Specification<Position> spec = DynamicSpecifications.bySearchFilter(filters.values(), Position.class);
        return spec;
    }

    @Transactional(readOnly = false)
    public void refresh(Long id, HrUser hrUser) {
        Date refreshDate = new Date();
        Date closeDate = DateUtils.addMonths(refreshDate, 2);
        positionDao.refresh(id, refreshDate, closeDate);
        saveHistory(id, hrUser, refreshDate);
    }

    @Transactional(readOnly = false)
    public void copyPosition(Long id, HrUser hrUser) {
        Position pos = positionDao.findOne(id);
        Position position = new Position(pos);
        position.setId(null);
        Date now = new Date();
        position.setPublishDate(now);
        position.setRefreshDate(now);
        position.setCloseDate(DateUtils.addMonths(now, 2));
        position.setStatus(Position.STATUS_ENABLED);
        positionDao.save(position);
        PositionHistory history = new PositionHistory(position, hrUser, now);
        positionHistoryDao.save(history);
    }

    public int homePositionCount = 10;
    public PageRequest homePageRequest = new PageRequest(0, homePositionCount, new Sort(Direction.DESC, "promotionHomepage"));
    public Specification<Position> homePageSpec = buildHomepageSpecification(null);

    private Specification<Position> buildHomepageSpecification(Map<String, Object> searchParams) {
        Map<String, SearchFilter> filters = null;
        if (searchParams == null) {
            filters = new HashMap<String, SearchFilter>();
        } else {
            filters = SearchFilter.parse(searchParams);
        }
        filters.put("status", new SearchFilter("status", Operator.LT, Position.STATUS_DELETED));
        Specification<Position> spec = DynamicSpecifications.bySearchFilter(filters.values(), Position.class);
        return spec;
    }

    public Page<Position> listHomepagePosition() {
        return positionDao.findAll(homePageSpec, homePageRequest);
    }

    public List<Position> getSameCompanyPosition(Long positionId, Long companyId, int count) {
        PageRequest pageRequest = buildPageRequest(1, count + 1, "auto", "d");
        Map<String, SearchFilter> filters = new HashMap<String, SearchFilter>();
        filters.put("company.id", new SearchFilter("company.id", Operator.EQ, companyId));
        filters.put("status", new SearchFilter("status", Operator.LT, Position.STATUS_DELETED));
        Specification<Position> spec = DynamicSpecifications.bySearchFilter(filters.values(), Position.class);
        Page<Position> positions = positionDao.findAll(spec, pageRequest);
        List<Position> result = new ArrayList<Position>();
        for (int i = 0; i < positions.getContent().size() && result.size() < count; i++) {
            if (positions.getContent().get(i).getId() != positionId) {
                result.add(positions.getContent().get(i));
            }
        }
        return result;
    }
}
